package utils;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

/**
 * This class manages file and folder operations - copy, move, in console or GUI mode.
 * 
 * @author Uros Krkic
 */
public final class FileManager {
	
	private static final int COPY_ACTION = 0;
	private static final int MOVE_ACTION = 1;

	private static RLMDataDirFilter filter = new RLMDataDirFilter();;
	
	
	private FileManager() {	}
	

	/**
	 * This method copies source folder to destination folder in console mode.
	 * @param source - source folder to be copied
	 * @param destination - destination folder to store copy
	 * @throws FileManagerException
	 * @author Uros Krkic
	 */
	public static void copyFolder(File source, File destination) throws FileManagerException {
		
		sourceDestinationChecker(source, destination);
		
		File[] files = source.listFiles(filter);
		
		if (files == null) {
			return;
		}
		
		for (int i = 0; i < files.length; i++) {
			File tempFile = new File(destination, files[i].getName());
			
			if (files[i].isDirectory() == true) {
				tempFile.mkdir();
				copyFolder(files[i], tempFile);
			}
			else {
				copyFile(files[i], tempFile);
			}
		}
	}

	
	/**
	 * This method moves source folder to destination folder in console mode.
	 * @param source - source folder to be moved
	 * @param destination - destination folder to store moving folder
	 * @throws FileManagerException
	 * @author Uros Krkic
	 */
	public static void moveFolder(File source, File destination) throws FileManagerException {
		
		sourceDestinationChecker(source, destination);
		
		File[] files = source.listFiles(filter);
		
		if (files == null) {
			return;
		}
		
		for (int i = 0; i < files.length; i++) {
			File tempFile = new File(destination, files[i].getName());
			
			if (files[i].isDirectory() == true) {
				tempFile.mkdir();
				moveFolder(files[i], tempFile);
			}
			else {
				copyFile(files[i], tempFile);
			}
			files[i].delete();
		}
	}
	
	
	
	/**
	 * This method copies source file to destination file in console mode.
	 * @param source - source file to be copied
	 * @param destination - destination file to store copy
	 * @throws FileManagerException
	 * @author Uros Krkic
	 */
	public static void copyFile(File sourceFile, File destFile) throws FileManagerException {
		try {
			InputStream in = new FileInputStream(sourceFile);
			OutputStream out = new FileOutputStream(destFile);

			byte[] buffer = new byte[1024];

			int length;

			while ( (length = in.read(buffer)) > 0 ) {
				out.write(buffer, 0, length);
			}
			
			in.close();
			out.close();
		}
		catch (FileNotFoundException fnfe) {
//			fnfe.printStackTrace();
			throw new FileManagerException(fnfe.getMessage());
		}
		catch (IOException ioe) {
//			ioe.printStackTrace();
			throw new FileManagerException(ioe.getMessage());
		}
	}
	
	
	/**
	 * This method moves source file to destination file in console mode.
	 * @param source - source file to be moved
	 * @param destination - destination file to store moving file
	 * @throws FileManagerException
	 * @author Uros Krkic
	 */
	public static void moveFile(File sourceFile, File destFile) throws FileManagerException {
		
		sourceDestinationChecker(sourceFile, destFile);
		
		copyFile(sourceFile, destFile);
		sourceFile.delete();
	}
	
	
	
	/**
	 * This method moves source folder to destination folder in GUI mode.
	 * @param source - source folder to be moved
	 * @param destination - destination folder to store moving folder
	 * @throws FileManagerException
	 * @author Uros Krkic
	 */
	public static void moveFolderGUI() throws FileManagerException {
		GUIFolderAction(MOVE_ACTION);
	}
	
	
	
	/**
	 * This method copies source folder to destination folder in GUI mode.
	 * @param source - source folder to be copied
	 * @param destination - destination folder to store copy
	 * @throws FileManagerException
	 * @author Uros Krkic
	 */
	public static void copyFolderGUI() throws FileManagerException {
		GUIFolderAction(COPY_ACTION);
	}
	
	
	
	private static void GUIFolderAction(int actionType) throws FileManagerException {
		File sourceFolder = null;
		File destinationFolder = null;
		
		JFileChooser sourceFileChooser = new JFileChooser();
		sourceFileChooser.setDialogTitle("Source Folder");
		sourceFileChooser.setApproveButtonText("OK");
		sourceFileChooser.setApproveButtonToolTipText("OK");
		sourceFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		sourceFileChooser.rescanCurrentDirectory();

		int sourceReturnValue = sourceFileChooser.showDialog(null, null);

		if (sourceReturnValue == JFileChooser.APPROVE_OPTION) {
			sourceFolder = sourceFileChooser.getSelectedFile();
		}
		
		
		JFileChooser destinationFileChooser = new JFileChooser();
		destinationFileChooser.setDialogTitle("Destination Folder");
		destinationFileChooser.setApproveButtonText("OK");
		destinationFileChooser.setApproveButtonToolTipText("OK");
		destinationFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		destinationFileChooser.rescanCurrentDirectory();

		int destReturnValue = destinationFileChooser.showDialog(null, null);

		if (destReturnValue == JFileChooser.APPROVE_OPTION) {
			destinationFolder = destinationFileChooser.getSelectedFile();
		}

		if (sourceFolder != null && destinationFolder != null) {
			switch ( actionType ) {
				case COPY_ACTION:
					copyFolder(sourceFolder, destinationFolder);
					break;
				case MOVE_ACTION:
					moveFolder(sourceFolder, destinationFolder);
					break;
			}
		}
		else {
			JOptionPane.showMessageDialog(null, "You must selecte source and destination folder !", "Move Folder Waring", JOptionPane.WARNING_MESSAGE);
			return;
		}
	}
	
	
	private static void sourceDestinationChecker(File source, File destination) throws FileManagerException {
		if (source.exists() == false) {
			throw new FileManagerException("The source does not exits !");
		}
		
		if (destination.canWrite() == false){
			throw new FileManagerException("The destination is read-only !");
		}
		
		if (destination.exists() == false) {
			throw new FileManagerException("The destination does not exits !");
		}
	}
	
	
	
	/**
	 * RLM data_dir filter.
	 * @author Uros Krkic
	 */
	private static class RLMDataDirFilter implements FileFilter {
		public boolean accept(File pathname) {
			return pathname.getAbsolutePath().contains("deploy");
		}
	}
	
	
	
	/**
	 * This method deletes source folder.
	 * @param source - folder to delete
	 * @throws FileManagerException
	 * @author Uros Krkic
	 */
	public static void deleteFolder(File source) throws FileManagerException {
		try {
			File[] files = source.listFiles();
			
			if (files == null) {
				return;
			}
			
			for (int i = 0; i < files.length; i++) {
				if (files[i].isDirectory() == true) {
					deleteFolder(files[i]);
				}
	
				files[i].delete();
			}
			
			source.delete();
		}
		catch (Exception e) {
			throw new FileManagerException(e.getMessage());
		}
	}
	
}
